package com.lm.menus;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

import com.lm.portlet.VideoPlayerPortlet;

/**
 * The parser for the <b>menu.xml</b> document. All the menus are saved in the {@link List} of {@link XmlMenu} object.
 * This class must be executed <b>each time</b> a <b>new</b> video is displayed in the video player.
 * If a video has already been displayed, the parser is not called.
 */
public class XmlMenuParser {
	static final String MENU = "menu";
	static final String HEIGHTVIDEO = "heightVideo";
	static final String WIDTHVIDEO = "widthVideo";
	static final String REFVIDEO = "refVideo";
	static final String NAMEVIDEO = "nameVideo";
	static final String KEYFRAME = "keyFrame";
	static final String IDKEYFRAME = "idKeyFrame";
	static final String TIMESTAMP = "timestamp";
	static final String DESCRIPTION = "description";
	static final String CLUSTER = "k";
	static List<com.lm.categories.XmlCategory> LISTCATEGORIES = com.lm.categories.XmlCategories.getInstance().getListCategories(); // Contains all the categories of the Singleton XmlCategories 
	static String DESCRIPTOR; //Contains one descriptor of the LISTCATEGORIES
//	static final String OTHERCATEGORY = "Other Settings";


/************************* Parseur *************************/

	/**
	 * Open the <b>menu.xml</b> document and read its content.
	 * @param menuFile
	 * 	The path of XML document.
	 * @param xmlMenu
	 * @param referenceVideo
	 * 	The reference of the wanted video.
	 * @return The {@link XmlKeyFrame} object.
	 * @throws XMLStreamException
	 * @throws IOException
	 */
	public static XmlMenu parse(String menuFile, XmlMenu xmlMenu) {
		XmlMenu xmlM = null;
		XMLInputFactory factory = XMLInputFactory.newInstance();
		InputStream is = null;
		XMLStreamReader reader = null;
		try {
			is = (new URL(menuFile)).openConnection().getInputStream();
			reader = factory.createXMLStreamReader(is);
			xmlM = readXmlMenu(reader, xmlMenu);
		} catch (IOException | XMLStreamException e) {
			e.printStackTrace();
		} finally { // Close the flow
			try {
				reader.close();
				is.close();
			} catch (IOException | XMLStreamException e) {
				e.printStackTrace();
			}
		}
		return xmlM;
	}
	
	/**
	 * Parse the XML document and transforms the menu into the Java objects ({@link XmlKeyFrame}).
	 * @param reader
	 * 	The position of the parser.
	 * @param xmlMenu
	 * @param referenceVideo
	 * 	The reference of the wanted video.
	 * @return The {@link XmlKeyFrame} object.
	 * @throws XMLStreamException
	 * @throws IOException
	 */
	public static XmlMenu readXmlMenu(XMLStreamReader reader, XmlMenu xmlMenu) throws XMLStreamException, IOException {
		String xmlMenuRefVideo = "";
		
		int idKeyFrame = 0;
		String timestamp = "";
		String description = "";
//		List<XmlCategory> listXmlCategories = null;
		
//		String xmlCategoryCategory = "";
		List<XmlSubMenu> listXmlSubMenus = null;
		
		boolean knownDescriptor = false;
		
		String xmlSubMenuTotalName = "";
		List<XmlCluster> listXmlCluster = null;
		
		String xmlClulsterSrc = "";
		
		String tagContent = "";
		
		while(reader.hasNext()){
			int event = reader.next();
			
			switch(event) {
			case XMLStreamConstants.START_ELEMENT:
				switch(reader.getLocalName()) {
				case MENU:
					if (reader.getAttributeValue(null, REFVIDEO) != null) {
						xmlMenuRefVideo = reader.getAttributeValue(null, REFVIDEO);
						xmlMenu.setReferenceVideo(xmlMenuRefVideo);
					} else {
						xmlMenu.setReferenceVideo("");
					}
					if (reader.getAttributeValue(null, NAMEVIDEO) != null) {
						xmlMenu.setNameVideo(reader.getAttributeValue(null, NAMEVIDEO));
					} else {
						xmlMenu.setReferenceVideo("");
					}
					String heightVideoTmp = reader.getAttributeValue(null, HEIGHTVIDEO);
					String widthVideoTmp = reader.getAttributeValue(null, WIDTHVIDEO);
					if (heightVideoTmp != null && !heightVideoTmp.equals("") && widthVideoTmp != null && !widthVideoTmp.equals("")) {
						xmlMenu.setHeightVideo(Integer.parseInt(heightVideoTmp));
						xmlMenu.setWidthVideo(Integer.parseInt(widthVideoTmp));
					} else {
						xmlMenu.setHeightVideo(9);
						xmlMenu.setWidthVideo(16);
					}
					
					xmlMenu.setListKeyFrames(new ArrayList<XmlKeyFrame>()); //Replace the listKeyFrames by a new one
					break;
				case KEYFRAME:
					String idKeyFrameTmp = reader.getAttributeValue(null, IDKEYFRAME);
					if (idKeyFrameTmp != null && !idKeyFrameTmp.equals("")) {
						idKeyFrame = Integer.parseInt(idKeyFrameTmp);
					} else {
						idKeyFrame = 0;
					}
					
					timestamp = reader.getAttributeValue(null, TIMESTAMP);
					description = reader.getAttributeValue(null, DESCRIPTION);
//					listXmlCategories = new ArrayList<XmlCategory>();
					listXmlSubMenus = new ArrayList<XmlSubMenu>();
					break;
//				case DESCRIPTOR:
//					break;
				case CLUSTER:
					if (reader.getAttributeValue(null, REFVIDEO) != null) {
						xmlClulsterSrc = reader.getAttributeValue(null, REFVIDEO);
					} else {
						xmlClulsterSrc = "";
					}
					break;
				default: //Search for the XmlDescriptor object corresponding with selected TAG
					if (knownDescriptor == false) {
						for (com.lm.categories.XmlCategory xmlCategory : LISTCATEGORIES) {
							for (com.lm.categories.XmlDescriptor xmlDescriptor : xmlCategory.getDescriptors()) {
								if (xmlDescriptor.getName().equals(reader.getLocalName())) { // We have found the correct XmlDescriptor
//									xmlCategoryCategory = xmlCategory.getName(); // Setup the category name
									DESCRIPTOR = xmlDescriptor.getName(); // Setup the Descriptor name
									xmlSubMenuTotalName = xmlDescriptor.getTotalName(); // Setup the Descriptor total name
									listXmlCluster = new ArrayList<XmlCluster>();
									knownDescriptor = true;
								}
							}
						} // Is the DESCRIPTOR does not exist in the XmlCategories list, it goes in the "OTHERCATEGORY" category.
//						if (xmlCategoryCategory.equals("")) {
						if (knownDescriptor == false) {
//							xmlCategoryCategory = OTHERCATEGORY;
							DESCRIPTOR = xmlSubMenuTotalName = reader.getLocalName();
							listXmlCluster = new ArrayList<XmlCluster>();
						}
					}
				}
				break;
				
			case XMLStreamConstants.CHARACTERS:
				tagContent = reader.getText().trim();
				break;
				
			case XMLStreamConstants.END_ELEMENT:
				switch(reader.getLocalName()) {
//				case MENU:
//					break;
				case KEYFRAME:
					xmlMenu.addKeyFrame(new XmlKeyFrame(idKeyFrame, timestamp, VideoPlayerPortlet.ADDRESS + VideoPlayerPortlet.ADDRESS_IMAGE + xmlMenuRefVideo + "_" + idKeyFrame + ".png", description, listXmlSubMenus));
					break;
//				case DESCRIPTOR:
//					break;
				case CLUSTER:
					listXmlCluster.add(new XmlCluster(Integer.parseInt(tagContent), VideoPlayerPortlet.ADDRESS + VideoPlayerPortlet.ADDRESS_VIDEO + xmlClulsterSrc + ".mp4"));					
					break;
				default: // It should be a DESCRIPTOR
					if (DESCRIPTOR.equals(reader.getLocalName())) {
						listXmlSubMenus.add(new XmlSubMenu(DESCRIPTOR, xmlSubMenuTotalName, listXmlCluster));
						knownDescriptor = false;
//						for (XmlCategory xmlCategory : listXmlCategories) {
//							if (xmlCategory.getCategory().equals(xmlCategoryCategory)) {
//								xmlCategory.getElements().add(new XmlSubMenu(DESCRIPTOR, xmlSubMenuTotalName, listXmlCluster));
//								xmlCategoryCategory = "";
//							}
//						}
//						if (!xmlCategoryCategory.equals("")) { // if xmlCategoryCategory has not been found in listXmlCategories, we create a new category
//							listXmlSubMenus = new ArrayList<XmlSubMenu>();
//							listXmlSubMenus.add(new XmlSubMenu(DESCRIPTOR, xmlSubMenuTotalName, listXmlCluster));
//							listXmlCategories.add(new XmlCategory(xmlCategoryCategory, listXmlSubMenus));
//							xmlCategoryCategory = "";
//						}
					}
				}
				break;
				
			case XMLStreamConstants.START_DOCUMENT:
//				xmlMenu = XmlMenu.getInstance();
				break;
			}
		}
		return xmlMenu;
	}
}